package com.pony.iphone.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pony.iphone.dto.QuestionAnswerDto;
import com.pony.iphone.dto.QuestionAnswerErrorDto;
import com.pony.iphone.entity.Library;
import com.pony.iphone.entity.Question;
import com.pony.iphone.mapper.LibraryMapper;
import com.pony.iphone.mapper.QuestionMapper;
import com.pony.iphone.service.QuestionService;
import com.pony.iphone.utils.AppHttpCodeEnum;
import com.pony.iphone.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author pony
 */
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService{

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private LibraryMapper libraryMapper;

    /**
     * 上传的一个问题以及其答案
     * @param questionAnswerDto lua 上传的数据
     * @return
     */
    @Override
    @Transactional
    public R upload(QuestionAnswerDto questionAnswerDto) {
        // 1、获取问题
        String questionStr = questionAnswerDto.getQuestion();
        System.out.println("上传的问题是：" + questionStr);

        List<String> answerList = questionAnswerDto.getAnswerList();
        answerList.forEach(answer -> System.out.println("上传的答案是：" + answer));

        // 2、查看数据库中是否有这个问题
        // 2-1、根据dto的题库名称查询是否有这个题库
        LambdaQueryWrapper<Library> libraryQw = new LambdaQueryWrapper<>();
        libraryQw.eq(Library::getName, questionAnswerDto.getLibraryName());
        Library library = libraryMapper.selectOne(libraryQw);
        // 如果没有查到题库
        if (library==null){
            return R.error(AppHttpCodeEnum.ERROR)
                    .message(questionAnswerDto.getLibraryName() + "，此题库不存在，请先创建此题库！");
        }
        // 2-2、如果查到了题库，则根据题库id和题目的名字，查询问题
        Question question = questionMapper.selectQuestionByLibraryIdAndQuestionName(library.getId(), questionStr);

        // 3、不存在的问题，则持久化到数据库
        if (question==null){
            boolean uploadResult = uploadQuestion(questionAnswerDto, library.getId());
            if (uploadResult){
                return R.success(AppHttpCodeEnum.SUCCESS, "单个问题上传成功！");
            }
            return R.error(AppHttpCodeEnum.ERROR, "单个问题上传失败！");
        }
        // 4、存在问题，不需要动
        return R.success(AppHttpCodeEnum.SUCCESS, "单个问题上传成功！");
    }

    /**
     * 获取一个问题的答案
     * @param questionAnswerDto
     * @return
     */
    @Override
    @Transactional
    public R getAnswer(QuestionAnswerDto questionAnswerDto) {
        // 1、获取问题和答案
        String questionStr = questionAnswerDto.getQuestion();
        List<String> answerList = questionAnswerDto.getAnswerList();

        // 2、先查询数据库中是否有这个问题
        LambdaQueryWrapper<Library> libraryQw = new LambdaQueryWrapper<>();
        libraryQw.eq(Library::getName, questionAnswerDto.getLibraryName());
        Library library = libraryMapper.selectOne(libraryQw);
        // 2-1、如果没有查到题库
        if (library==null){
            return R.error(AppHttpCodeEnum.ERROR)
                    .message(questionAnswerDto.getLibraryName() + "，此题库不存在，请先创建此题库！");
        }
        // 2-2、如果查到了题库，则根据题库id和题目的名字，查询问题
        Question question = questionMapper.selectQuestionByLibraryIdAndQuestionName(library.getId(), questionStr);

        if (question==null){
            System.out.println("没有找到问题");
        }else {
            System.out.println(question.toString());
        }

        // 3、没有问题，则将新问题存到数据库并随机选择一个答案选择
        if (question==null){
            boolean uploadResult = uploadQuestion(questionAnswerDto, library.getId());
            // 将新问题添加到数据库，成功，返回一个随机的答案
            if (uploadResult){
                return R.success(AppHttpCodeEnum.SUCCESS)
                        .message("这是一个新问题，新问题上传成功，并返回一个随机的选项")
                        .data("answer", questionAnswerDto.getRandomAnswer());
            }
            // 将新问题添加到数据库，失败，返回一个随机的答案
            return R.error(AppHttpCodeEnum.ERROR)
                    .message("单个问题上传失败！")
                    .data("answer", questionAnswerDto.getRandomAnswer());
        }else { // 4、有这个问题，根据选择权重较大的选项返回
            return R.success(AppHttpCodeEnum.SUCCESS)
                    .message("问题已经存在数据库，返回一个权重较大的选项")
                    .data("answer", question.getWeightAnswer());
        }
    }

    /**
     * 整个答题链路，失败的处理，将本次答题链路，所选的答案的分数加1，然后存到数据库中
     * @param questionAnswerErrorDtoList 整个答题链路，包含所有问题和与之对应的所有答案选项
     * @return R
     */
    @Override
    @Transactional
    public R uploadError(ArrayList<QuestionAnswerErrorDto> questionAnswerErrorDtoList) {
        // 1、将dtoList所有的问题，组成一个集合
        List<String> questions = questionAnswerErrorDtoList.stream()
                .map(QuestionAnswerErrorDto::getQuestion)
                .toList();

        // 2、批量查询所有相关的问题以及答案
        // 2-1、先查询有没有题库
        String libraryName = questionAnswerErrorDtoList.get(0).getLibraryName();
        LambdaQueryWrapper<Library> libraryQw = new LambdaQueryWrapper<>();
        libraryQw.eq(Library::getName, libraryName);
        Library library = libraryMapper.selectOne(libraryQw);
        // 如果没有查到题库
        if (library==null){
            return R.error(AppHttpCodeEnum.ERROR)
                    .message(libraryName + "，此题库不存在，请先创建此题库！");
        }
        // 2-2、如果查到了题库，则根据题库id 和 dto题目的问题名字list，查询范围内问题列表
        List<Question> questionList = questionMapper.selectQuestionsByLibraryIdAndQuestionList(library.getId(),questions);
        System.out.println("数据库查询到的问题列表：");
        System.out.println(questionList);
        // 3、构建问题映射，List -> Map，问题作为key，流本身作为value
        Map<String, Question> questionMap = questionList.stream()
                .collect(Collectors.toMap(Question::getQuestion, Function.identity()));

        System.out.println("问题集合是：" + questionMap);

        // 4、根据问题文本找到，questionMap中的问题对象，然后对应选项的分数+1，重新组合数据到list中
        // 最终组装的questionList
        List<Question> updateQuestionList = new ArrayList<>();

        for (QuestionAnswerErrorDto errorDto : questionAnswerErrorDtoList) {
            System.out.println("dto是：" + errorDto.toString());
            // 获取 dto 问题
            String questionStr = errorDto.getQuestion();
            System.out.println("dto-问题是：" + errorDto.toString());
            // 获取 dto 答案
            String selectedAnswer = errorDto.getAnswer();
            System.out.println("dto-答案是：" + selectedAnswer);

            // 4-1、根据 dto 问题文本，从 map 中查询出question对象
            Question question = questionMap.get(questionStr);
            System.out.println("参数判断");
            System.out.println(question);
            System.out.println(question.getAnswer());
            // 检查问题是否存在且 answer 不为 null
            if (question != null && question.getAnswer() != null) {
                HashMap<String, Long> answerMap = question.getAnswer();
                // 检查答案选项是否存在
                if (answerMap.containsKey(selectedAnswer)) {
                    // 4-2、将选中答案的分数+1
                    answerMap.put(selectedAnswer, answerMap.get(selectedAnswer) + 1);
                    // 4-3、组装新数据到list中
                    updateQuestionList.add(question);
                }
            }
        }

        System.out.println("更新后的问题：");
        System.out.println(updateQuestionList);
        updateQuestionList.forEach(question -> System.out.println("更新后的问题：" + question.toString()));
        // 5、批量更新
        if (CollectionUtils.isNotEmpty(questions)) {
            updateBatchById(updateQuestionList);
        }

        return R.success(AppHttpCodeEnum.SUCCESS, "答题链路处理完成");
    }

    /**
     * 上传单个问题以及所有答案 到数据库 中
     * @param questionAnswerDto 前端传的问题
     * @return 新插入问题的ID，如果插入失败则返回null
     */
    public boolean uploadQuestion(QuestionAnswerDto questionAnswerDto, Long libraryId){
        // 答案选项
        List<String> answerList = questionAnswerDto.getAnswerList();
        HashMap<String, Long> answerMap = new HashMap<>();
        // 1、组装数据
        Question newQuestion = new Question();
        newQuestion.setQuestion(questionAnswerDto.getQuestion());
        // 新题的选项的分数都是0
        answerList.forEach(answer -> answerMap.put(answer, 0L));
        newQuestion.setAnswer(answerMap);
        // 2、持久化到数据库
        // 2-1、根据题库id 和 问题查询数据库，有没有这个问题
        Question questionRes = questionMapper.selectQuestionByLibraryIdAndQuestionName(libraryId, questionAnswerDto.getQuestion());

        // 表的变化行数，1表示添加成功成功
        int insertLib;
        // 如果没有找到问题，则添加
        if (questionRes == null){
            // 2-2、问题表添加这个问题
            int insert = questionMapper.insert(newQuestion);
            if (insert != 1) {
                // 返回新插入问题的ID
                return false;
            }
            // 2-3、题库库表添加这个问题
            insertLib = libraryMapper.addQuestionForLibrary(libraryId, newQuestion.getId());
        }else {
            insertLib = 1;
        }
        return insertLib == 1;
//        // 2-1、查询问题表，查看这个问题是否存在
//        Question question = questionMapper.selectQuestionByLibraryIdAndQuestionName(libraryId, questionAnswerDto.getQuestion());
//        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(Question::getQuestion, questionAnswerDto.getQuestion());
//        Question questionRes = questionMapper.selectOne(queryWrapper);
//
//        int insertLib;
//        // 问题表没有这个问题，则添加，没必要在问题表中添加重复的问题
//        if (questionRes == null){
//            // 2-2、问题表添加这个问题
//            int insert = questionMapper.insert(newQuestion);
//            if (insert != 1) {
//                // 返回新插入问题的ID
//                return false;
//            }
//            // 2-3、题库库表添加这个问题
//            insertLib = libraryMapper.addQuestionForLibrary(libraryId, newQuestion.getId());
//        }else {
//            // 问题表有这个问题，则添加关系表就行了
//            insertLib = libraryMapper.addQuestionForLibrary(libraryId, questionRes.getId());
//        }
    }
}
